﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cylong.Cache.json;
using Enyim.Caching;
using Enyim.Caching.Memcached;
namespace Cylong.Cache
{
    /// <summary>
    /// MemcahceCache
    /// </summary>
    public class MemcahceCache: ICacheProvider
    {
        private static Lazy<MemcachedClient> _memcache = new Lazy<MemcachedClient>(
                () =>
                {
                    return new MemcachedClient();
                });

        /// <summary>
        /// 客户端
        /// </summary>
        public MemcachedClient MC
        {
            get
            {
                return _memcache.Value;
            }
        }


        public static MemcahceCache GetCache()
        {
            return new MemcahceCache();
        }

        public MemcahceCache()
        {
        }

        private bool IsObjectType(Type type)
        {
            return type.IsClass || type.IsInterface;
        }

        /// <summary>
        ///  
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheKey"></param>
        /// <returns></returns>
        public T Get<T>(string cacheKey)
        {
            if (IsObjectType(typeof(T)))
            {
                var obj = MC.Get(cacheKey);
                if (obj == null)
                    return default(T);
                if (obj is T)
                    return (T)obj;

                return MC.Get<string>(cacheKey).Deserialize<T>();
            } 
            return MC.Get<T>(cacheKey);
        }

        public object Get(string cacheKey)
        {
            return MC.Get(cacheKey);
        }

        /// <summary>
        /// 写入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <remarks>有效期默认为24小时</remarks>
        /// <returns></returns>
        public bool Write<T>(string cacheKey, T value)
        {
            return Write(cacheKey, value, TimeSpan.FromHours(24));
        }

        /// <summary>
        /// 更新缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">缓存建</param>
        /// <param name="t">缓存值</param> 
        /// <remarks>更新缓存</remarks>
        /// <returns></returns>
        public bool Update<T>(string key, T t)
        {
            bool b = this.Remove(key);
            if (b == true)
            {
                return this.Write<T>(key, t);
            }
            return false;
        }

        /// <summary>
        /// 写入Memcache，有过期时间
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="cacheKey"></param>
        /// <param name="value"></param>
        /// <param name="expireTime"></param>
        /// <remarks>Class 和 Interface类型会转换成JSON</remarks>
        /// <returns></returns>
        public bool Write<T>(string cacheKey, T value, TimeSpan expireTime)
        {
            if (IsObjectType(typeof(T)))
            {
                var str = value.ToJson();
                MC.Store(StoreMode.Set, cacheKey, str, expireTime);
            }
            return MC.Store(StoreMode.Set, cacheKey, value, expireTime);
        }

        public bool Remove(string cacheKey)
        {
            return MC.Remove(cacheKey);
        }

        /// <summary>
        /// 清空缓存
        /// </summary>
        public virtual void FlushCache()
        {
            MC.FlushAll();
        }

        /// <summary>
        /// 是否存在该缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public virtual bool IsExists(string key)
        {
            return MC.Get(key) != null;
        }


        /// <summary>
        /// 设置缓存
        /// </summary> 
        /// <param name="key">缓存Key</param> 
        /// <param name="setFunc">缓存</param> 
        /// <author>xiao</author>
        /// <remarks></remarks>
        /// <returns></returns>
        public T GetOrAdd<T>(string key, Func<string, T> setFunc) where T : class
        {
            object obj;
            if (MC.TryGet(key, out obj))
            {
                return Get<T>(key);
            }
            else
            {
                MC.Remove(key);
                obj = setFunc(key);

                MC.Store(StoreMode.Set, key, obj.ToJson());
                return obj as T;
            }
        }
    }
}

